From e0b2c3cf9476b25e317b7fcfa63b7accc34f054c Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20H=C3=A4rdeman?= Date: Sat, 20 Sep 2025 23:19:29 +0200 Subject: [PATCH] odhcpd: allow assignments to be reassigned MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit In a nutshell, this allows static leases which have only been configured with a DUID (so no IAID specified) to be reassigned to any client with the same DUID (but potentially different IAID). This matches how multiple MAC addresses are handled in the DHCPv4 case, and supports the use case for e.g. moving from WiFi to ethernet. On the other hand, it is probably not what one would want for e.g. a server that has several NICs connected to the same network. For those cases, defining static leases with DUID and IAID anyway seems preferrable (and it will also ensure a static interface<->IPv6 addr mapping). Signed-off-by: David Härdeman Link: https://github.com/openwrt/odhcpd/pull/255 Signed-off-by: Álvaro Fernández Rojas --- src/dhcpv6-ia.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index f24f14c..1bdcfd3 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -1519,8 +1519,42 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac continue; /* Does the IAID match? */ - if (c->iaid != ia->iaid) - continue; + if (c->iaid != ia->iaid) { + if (is_pd) + continue; + + /* Does the existing assignment stem from the same static lease cfg? */ + if (c->lease != l) + continue; + + /* + * If there's a DUID configured for this static lease, but without + * an IAID, we will proceed under the assumption that a request + * with the right DUID but with *any* IAID should be able to take + * over the assignment. E.g. when switching from WiFi to ethernet + * on the same client. This is similar to how multiple MAC adresses + * are handled for DHCPv4. + */ + for (size_t i = 0; i < l->duid_count; i++) { + if (l->duids[i].iaid_set && l->duids[i].iaid != htonl(ia->iaid)) + continue; + + if (l->duids[i].len != clid_len) + continue; + + if (memcmp(l->duids[i].id, clid_data, clid_len)) + continue; + + /* + * Reconf doesn't specify the IAID, so we have to assume the client + * already knows or doesn't care about the old assignment. + */ + stop_reconf(c); + free_assignment(c); + goto proceed; + } + continue; + } /* We have a match */ a = c; @@ -1538,6 +1572,7 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac a = NULL; } +proceed: /* Generic message handling */ uint16_t status = DHCPV6_STATUS_OK; if (a && a->managed_size < 0) -- 2.30.2